home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
extbind.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
18KB
|
768 lines
/*
* $Id: extbind.c,v 0.91 1994/02/20 00:53:17 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Purpose:
* Handles external bindings. See Doc for formats specifications
*
* Code is slightly complicated by the fact that we can not simply
* create a double-ended pipe to do IO because we MUST guarantee
* fseek-ablity.
*/
#if !defined(lint) && defined (F_ID)
char *id_extb = "$Id: extbind.c,v 0.91 1994/02/20 00:53:17 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
#include "dmalloc.h"
/*******************************************************************
* External convolution kernels
****************************************************************{*/
/******************* Limits **********************************/
#define MAXCONV 35 /* max no. of extern matrices */
/************************************************************
* structures for external kernel and associated functions
************************************************************/
typedef struct
{
char *name; /* name of the kernel */
int rows, cols; /* matrix and its order(square) */
int **m; /* the matrix */
}
ext_convolv_t;
/*************************************************************
* free an ext_convolve: name & matrix
*************************************************************/
static void
ec_free(ext_convolv_t * p)
{
if (p->name)
{
free(p->name);
p->name = 0;
}
p->rows = p->cols = 0;
free_mat(p->m);
p->m = 0;
}
/*************************************************************
* ext_convolve struct copy
************************************************************/
static void
ec_dup(ext_convolv_t * to, const ext_convolv_t * from)
{
to->name = strdup(from->name);
to->rows = from->rows;
to->cols = from->cols;
to->m = get_mat(to->rows, to->cols, sizeof(int));
memcpy(to->m[0], from->m[0], sizeof(int) * to->rows * to->cols);
}
/**************************************************************
* if two definations are identical
**************************************************************/
/* rather loose, if same name and same rank, consider same */
static int
ec_identical(const ext_convolv_t * a, const ext_convolv_t * b)
{
return (a->rows == b->rows &&
a->cols == b->cols &&
strcmp(a->name, b->name) == 0);
}
/************* Variables and functions ************************/
static ext_convolv_t convolv[MAXCONV];
static IPTR iptr; /* local copy of input image ptr */
static int ec_scanner(void);
static void ec_doit(long);
/*************************************************************
* The global entry point for external convolution
*************************************************************/
int
do_ext_convolv(IPTR im)
{
static int nkernel, action = -1;
int i;
iptr = im;
if (!image_ready(im, "ExtConvolv"))
return -1;
if (!nkernel && (nkernel = ec_scanner()) <= 0)
{
help_cb(0, HELP_CONVOLV);
return -1;
}
/* make action table */
if (action < 0)
{
action = define_action("Convolution", "convolv.hlp");
for (i = 0; i < nkernel; i++)
addto_action(action, convolv[i].name, ec_doit);
}
/* that is it */
do_action(action);
return 0;
}
/***************************************************************
* do_ec actually does the convolution by calling img_convolve.
* do_action will invoke ec_doit.
***************************************************************/
static void
ec_doit(long p)
{
ext_convolv_t *q = convolv + p;
if (img_convolv(iptr, q->m, q->rows, q->cols, (int *) 0,
img_rect(iptr), q->name) >= 0)
{
update_image_info(iptr);
iptr->io->display(iptr, 4, 1);
}
}
/****************************************************************
* Free all ec
****************************************************************/
void
free_all_ext_convolv(void)
{
ext_convolv_t *ec = convolv + MAXCONV;
while (--ec > convolv)
ec_free(ec);
}
/*********************************************************************
* remove redundant entries. Need to do this because external matrices
* are loaded from SysDir and UserDir
*********************************************************************/
static int
ec_uniq(void)
{
static int ok, uniq = 1; /* we have at least one uniq */
ext_convolv_t *p = convolv, *ps;
int i, found;
if (ok)
return uniq;
p++;
for (ps = p - 1 + MAXCONV; p < ps && p->name; p++)
{
/* search for in uniqued array */
for (i = found = 0; !found && i < uniq; i++)
found = ec_identical(p, convolv + i);
if (!found)
{
if (convolv[i].name != p->name) /* not the same */
{
ec_free(convolv + uniq);
ec_dup(convolv + uniq, p);
ec_free(p);
}
uniq++;
}
else
{ /* redundant */
ec_free(p);
}
}
ok = 1;
return uniq;
}
/******* scan string for matrix: n,n,n,n,n,n *****/
static int **
scan_matrix(int n, char *str)
{
int err = 0, c, k = 0, len = strlen(str);
int **mm = get_mat(n, n, sizeof(int)), *m, *ms;
if (mm)
{
m = mm[0];
for (ms = m + n * n, err = k = 0; !err && m < ms && k < len; m++)
{
err = (sscanf(str + k, " %d ,%n", m, &c) < 1);
k += c;
}
}
if (err)
{
free_mat(mm);
return 0;
}
return mm;
}
/****** read a external kernel defination file from stream fp ** **/
#define ECFMT "@ %[^;]; %d ; %[^;];"
static int
ec_scanner_fp(FILE * fp, int start)
{
int order = 0, sofar = start, err = 0;
char line[256], name[256], nm[256];
while (fgets(line, sizeof(line), fp))
{
if (line[0] != '@')
continue;
err = (sscanf(line, ECFMT, name, &order, nm) < 3);
/* skip if anything wrong */
if (err || !name[0] || order <= 0 || order > 10 || !nm[0])
{
M_warn("EXTCONV", "Bad line %s\n \tname=%s\torder=%d",
line, name, order);
}
else
{
convolv[sofar].name = strdup(name);
convolv[sofar].rows = order;
convolv[sofar].cols = order;
if ((convolv[sofar].m = scan_matrix(order, nm)))
{
sofar++;
}
else
{
M_err("", "Bad matrix: %s", nm);
}
sofar %= MAXCONV;
}
}
/* number of correct entries read */
return sofar - start;
}
/******** Read definations from UserDir and SysDir */
static int
ec_scanner(void)
{
FILE *fp;
int total = 0;
static const char *convolvfile = "BIT_convolve";
/* try the system directory first */
if ((fp = get_HELPfile_fp(convolvfile, "r")))
{
total = ec_scanner_fp(fp, 0);
#ifdef MDEBUG
M_debug("ExtConvolv", "%d matrices read from %s", total, helppath);
#endif
fclose(fp);
}
/* try user directory */
if ((fp = get_BITfile_fp(convolvfile, "r")))
{
total += ec_scanner_fp(fp, total >= 0 ? total : 0);
#ifdef MDEBUG
M_debug("ExtConvolv", "Total %d matrices read", total);
#endif
fclose(fp);
}
/* remove reduandant definations */
if (total)
{
total = ec_uniq();
}
else
{
M_err("ExtConvolv", "error reading %s from %s", convolvfile, bitpath);
M_err("ExtConvolv", "error reading %s from %s", convolvfile, helppath);
Bark("ExtConvolv", "No valid convolution matrix found");
}
M_info("ExtConvolv", "Total %d unique matrices read", total);
return total;
}
/*****************************************************************
* END of External Convolution Kernel routine
************************************************************}***/
/****************************************************************
* Handle external filters as if the following is done:
* dump | ext_filter | load
*
* the actual process is done in two steps
* 1. external_filter > filtered_output
* 2. load filtered_output
*
* This is still not strictly correct because what we really
* want is a 3 step process:
* 1. write currentimage > tmp
* 2. external_filter tmp > output
* 3. load output
*
* well, until someone complains
***************************************************************/
/*************** Limits *****************************/
#define MAX_B 35 /* no. of bindings */
#define MAXFFMT 4 /* no. formats each B accepts */
#define MAXTOK 125 /* max name, label, whatever */
/********* Structure for bindings ****************/
typedef struct
{
char *title, *pname, *opt; /* title, program, option */
char *infmt[MAXFFMT + 1]; /* format, ppm, gif, etc */
int in; /* index into the img_io struct */
}
ext_filter_t;
/************ Variables and functions ***********/
static ext_filter_t filter[MAX_B];
static char *swapfile;
static char *ef_cmd; /* current command */
extern FILE *popen(const char *, const char *);
#include <signal.h>
#include <setjmp.h>
static jmp_buf jpipe; /* for error recovery */
#if defined (__STRICT_ANSI__) && !defined(__sgi__)
typedef void (*SIG_PF) (int,...);
#endif
static SIG_PF opipe;
static int ef_scanner(void);
static void ef_pipe(int);
static void ef_doit(long);
/****************************************************
* Global interface for external filters
******************************************************/
int
do_ext_filter(IPTR im)
{
static int nfs, bindex = -1;
iptr = im;
if (nfs <= 0 && (nfs = ef_scanner()) <= 0)
{
help_cb(0, HELP_FILTER);
return -1;
}
/* make the action table */
if (bindex < 0)
{
ext_filter_t *p = &filter[0], *ps;
char *label;
bindex = define_action("ExternFilter", "filter.hlp");
for (ps = p + nfs; p < ps; p++)
{
label = p->title ? p->title : p->pname;
if (addto_action(bindex, label, ef_doit) < 0)
M_warn("Scanner", "addto_action failed for %s", label);
}
}
if (bindex < 0)
{
Bark("ExtFilter", "Something is wrong");
return -1;
}
/* take over the pipe handler */
opipe = signal(SIGPIPE, ef_pipe);
(void) setjmp(jpipe);
/* fireworks here */
do_action(bindex);
/* restore old handler */
(void) signal(SIGPIPE, opipe);
return 0;
}
/*******************************************************************
* The beef: actual work is done here. Really wish there were a
* snprintf function which will make this routine much safer.
*******************************************************************/
static const char *pref = ".BIT";
#ifdef __STRICT_ANSI__
extern int pclose(FILE *);
#endif
static void
ef_doit(long a)
{
char cmd[3 * MAXTOK], *opt;
int in;
IPTR local;
ext_filter_t *p;
IMG_IO *io;
p = filter + a;
/* find the best match from the list of needed formats */
if ((in = best_format(iptr, p->infmt)) < 0)
{
Bark("ExtFilter", "BadFmt _%s_", p->infmt[0] ? p->infmt[0] : "None");
return;
}
io = img_io + in;
/* convert to the needed types if different */
if (io->type != T_FLEX && iptr->type != io->type &&
img_convert_type(iptr, io->type))
return;
if (!(swapfile = get_tmpf(pref)))
{
Bark("ExtBind", "unable to create tmpfile");
return;
}
/* check if interactive command line options */
if ((opt = p->opt) && strcmp(opt, "?") == 0)
{
const char *q;
sprintf(cmd, "Options for %s", p->pname);
if ((q = getstring(cmd, "", 1)))
opt = strdup(q);
check_emergency();
}
/* generate the shell command on the fly */
ef_cmd = p->pname;
sprintf(cmd, "%s %s > %s", p->pname, opt ? opt : "", swapfile);
if (opt != p->opt)
free(opt);
M_info("pipe", "executing %s", cmd);
if (!(iptr->fp = popen(cmd, "w")))
return;
/* need to save the original filename before dump */
Strncpy(cmd, iptr->ifile, sizeof(cmd));
io->dump(iptr);
/**** wait until pipe closes ***************/
show_busy("PleaseWait ...");
(void) pclose(iptr->fp);
end_busy();
/******* So far so good, try to load it ****/
set_current_window(win_id);
/* service Q first before doing anything else */
check_emergency();
/* load the image and replace the old one if successful * */
if ((local = load_image(swapfile)))
{ /* ok */
free_image_mem(iptr); /* must not free iptr itself */
memcpy(iptr, local, sizeof(*iptr));
free(local);
}
del_tmpf(swapfile);
Strncpy(iptr->ifile, cmd, TC_FL);
update_filename(iptr->ifile);
iptr->io->display(iptr, 3, 1);
}
/************** Free an ext binding ***************/
static void
ef_free(ext_filter_t * p)
{
char **q = p->infmt;
Free(p->title);
Free(p->pname);
Free(p->opt);
while (*q)
{
free(*q);
*q = 0;
q++;
}
}
/************** Free all ext binding ***************/
void
free_all_ext_filter(void)
{
ext_filter_t *p = filter + MAX_B;
while (--p >= filter)
ef_free(p);
}
/******* make a copy of the ext_filter **************/
static void
ef_dup(ext_filter_t * to, ext_filter_t * from)
{
char **tof, **fromf;
to->title = strdup(from->title);
to->pname = strdup(from->pname);
to->opt = strdup(from->opt);
fromf = from->infmt;
tof = to->infmt;
while (*fromf)
{
*tof = strdup(*fromf);
fromf++;
tof++;
}
*tof = 0;
}
/******************************************************************
* remove redundant definitions. we need to do this because BIT loads
* definitions from sys dir and user dir
*****************************************************************/
static int
ef_uniq(void)
{
ext_filter_t *p = filter, *ps;
static int uniq = 1; /* will at least have on uniq entry */
static int ok;
int i, found;
if (ok)
return uniq;
p++;
for (ps = p + MAX_B - 1; p < ps && p->title; p++)
{
/* search thru uniq so far */
for (i = found = 0; !found && i < uniq; i++)
found = strcmp(p->title, filter[i].title) == 0 &&
strcmp(p->pname, filter[i].pname) == 0;
if (!found)
{ /* move it */
if (filter[uniq].title != p->title)
{
ef_free(filter + uniq);
ef_dup(filter + uniq, p);
ef_free(p);
}
++uniq;
}
else
{
ef_free(p);
}
}
ok = 1;
return uniq;
}
#define EFFMT "@%[^;];%[^;];%[^;];%[^;];%n"
static int
ef_scanner_fp(FILE * fp, int start)
{
char line[MAXTOK], blab[MAXTOK], prgm[MAXTOK];
char opt[MAXTOK], inf[MAXTOK];
ext_filter_t *p;
int err = 0, in, n, kfmt, sofar = start;
while (fgets(line, MAXTOK, fp))
{
if (line[0] != '@')
continue;
err = (sscanf(line, EFFMT, blab, prgm, opt, inf, &n) < 4);
space_de(de_space(prgm));
space_de(de_space(blab));
space_de(de_space(opt));
space_de(de_space(inf));
#ifdef MTRACE
M_trace("EB", "L=%s P=%s O=%s F=%s", blab, prgm, opt, inf);
#endif
err = err || (!prgm[0] || !inf[0]);
if (!err)
{
p = &filter[sofar]; /* sofar will never out of bounds */
p->title = strdup(blab[0] ? blab : prgm);
p->pname = strdup(prgm);
p->opt = opt[0] ? strdup(opt) : 0;
p->infmt[0] = strdup(inf);
/* now get alternate formats */
err = 0;
kfmt = 1;
while (!err && kfmt < MAXFFMT && n < strlen(line) - 1)
{
err = sscanf(line + n, "%[^;];%n", inf, &in) <= 0;
space_de(de_space(inf));
n += in;
if (!err)
{
p->infmt[kfmt] = strdup(inf);
kfmt++;
}
}
/* important. Best_format depends on this */
p->infmt[MAXFFMT] = 0;
sofar++;
sofar %= MAX_B;
}
else
{
M_warn("EB", "bad line %s\n\ttitle: %s", line, blab);
M_warn("EB", "\tpname:%s\n\t opt:%s\t inf:%s",
prgm, opt, inf);
}
blab[0] = prgm[0] = opt[0] = inf[0] = '\0';
}
return sofar - start;
}
static int
ef_scanner(void)
{
int sofar = 0;
static const char *filterfile = "BIT_filters";
FILE *fp;
#ifdef MTRACE
M_trace("EF_scanner", "Entering");
#endif
if ((fp = get_HELPfile_fp(filterfile, "r")))
{
sofar = ef_scanner_fp(fp, 0);
(void) fclose(fp);
M_info("ExtFilter", "%d bindings read from %s", sofar, helppath);
}
if ((fp = get_BITfile_fp(filterfile, "r")))
{
sofar += ef_scanner_fp(fp, sofar >= 0 ? sofar : 0);
(void) fclose(fp);
M_info("ExtFilter", "total %d bindings read from", sofar, bitpath);
}
#ifdef MTRACE
M_trace("EF_scanner", "Exit");
#endif
/* check to make sure there are no repeat entries */
if (sofar)
{
sofar = ef_uniq();
}
else
{
M_err("ExtFilter", "error reading %s from %s", filterfile, bitpath);
M_err("ExtFilter", "error reading %s from %s", filterfile, helppath);
Bark("ExtFilter", "No valid filters defined");
}
M_info("ExtFilter", "Total %d unique bindings read", sofar);
return sofar;
}
/*************************************************************
* All errors during execution of the filter will end-up here
************************************************************/
static void
ef_pipe(int sig)
{
#ifdef MTRACE
M_trace("EB_pipe", "Entering");
#endif
if (sig != SIGPIPE)
{
Bark("EB_pipe", "Something is very wrong");
clean_up();
}
Bark("ExtBind", "%s: Something is wrong in pipe", ef_cmd);
remove_progress_report();
fl_activate_all_forms();
signal(SIGPIPE, ef_pipe);
del_tmpf(swapfile);
#ifdef MTRACE
M_trace("EB_pipe", "Exit");
#endif
longjmp(jpipe, 1);
}